// r.d(t, { I: () => TilesRenderer });
import path from "path"
class LRUCache {
  maxSize: number
  minSize: number
  unloadPercent: number
  itemSet: Map<any, any>
  itemList: any[]
  usedSet: Set<any>
  callbacks: Map<any, any>
  unloadPriorityCallback: any
  defaultPriorityCallback: (t: any) => any
  scheduled: any
  constructor() {
    ;(this.maxSize = 800),
      (this.minSize = 600),
      (this.unloadPercent = 0.05),
      (this.itemSet = new Map()),
      (this.itemList = []),
      (this.usedSet = new Set()),
      (this.callbacks = new Map()),
      (this.unloadPriorityCallback = null)
    const e = this.itemSet
    this.defaultPriorityCallback = t => e.get(t)
  }
  isFull() {
    return this.itemSet.size >= this.maxSize
  }
  add(e, t) {
    const r = this.itemSet
    if (r.has(e)) return !1
    if (this.isFull()) return !1
    const s = this.usedSet,
      n = this.itemList,
      i = this.callbacks
    return n.push(e), s.add(e), r.set(e, Date.now()), i.set(e, t), !0
  }
  remove(e) {
    const t = this.usedSet,
      r = this.itemSet,
      s = this.itemList,
      n = this.callbacks
    if (r.has(e)) {
      n.get(e)(e)
      const i = s.indexOf(e)
      return s.splice(i, 1), t.delete(e), r.delete(e), n.delete(e), !0
    }
    return !1
  }
  markUsed(e) {
    const t = this.itemSet,
      r = this.usedSet
    t.has(e) && !r.has(e) && (t.set(e, Date.now()), r.add(e))
  }
  markAllUnused() {
    this.usedSet.clear()
  }
  unloadUnusedContent() {
    const e = this.unloadPercent,
      t = this.minSize,
      r = this.itemList,
      s = this.itemSet,
      n = this.usedSet,
      i = this.callbacks,
      o = r.length - n.size,
      a = r.length - t,
      l = this.unloadPriorityCallback || this.defaultPriorityCallback
    if (a > 0 && o > 0) {
      r.sort((e, t) => {
        const r = n.has(e),
          s = n.has(t)
        return r && s ? 0 : r || s ? (r ? 1 : -1) : l(t) - l(e)
      })
      const c = Math.min(a, o),
        h = Math.max(t * e, c * e)
      let u = Math.min(h, o)
      u = Math.ceil(u)
      const d = r.splice(0, u)
      for (let e = 0, t = d.length; e < t; e++) {
        const t = d[e]
        i.get(t)(t), s.delete(t), i.delete(t)
      }
    }
  }
  scheduleUnload(e = !0) {
    var t
    this.scheduled ||
      ((this.scheduled = !0),
      (t = () => {
        ;(this.scheduled = !1), this.unloadUnusedContent(), e && this.markAllUnused()
      }),
      Promise.resolve(t))
  }
}
class PriorityQueue {
  maxJobs: number
  items: any[]
  callbacks: Map<any, any>
  currJobs: number
  scheduled: boolean
  autoUpdate: boolean
  priorityCallback: any
  constructor() {
    ;(this.maxJobs = 6),
      (this.items = []),
      (this.callbacks = new Map()),
      (this.currJobs = 0),
      (this.scheduled = !1),
      (this.autoUpdate = !0),
      (this.priorityCallback = () => {
        throw new Error("PriorityQueue: PriorityCallback function not defined.")
      })
  }
  sort() {
    const e = this.priorityCallback
    this.items.sort(e)
  }
  add(e, t) {
    return new Promise((r, s) => {
      const n = this.items,
        i = this.callbacks
      n.push(e),
        i.set(e, (...e) =>
          t(...e)
            .then(r)
            .catch(s)
        ),
        this.autoUpdate && this.scheduleJobRun()
    })
  }
  remove(e) {
    const t = this.items,
      r = this.callbacks,
      s = t.indexOf(e)
    ;-1 !== s && (t.splice(s, 1), r.delete(e))
  }
  tryRunJobs() {
    this.sort()
    const e = this.items,
      t = this.callbacks,
      r = this.maxJobs
    let s = this.currJobs
    for (; r > s && e.length > 0; ) {
      s++
      const r = e.pop(),
        n = t.get(r)
      t.delete(r),
        n(r)
          .then(() => {
            this.currJobs--, this.autoUpdate && this.scheduleJobRun()
          })
          .catch(() => {
            this.currJobs--, this.autoUpdate && this.scheduleJobRun()
          })
    }
    this.currJobs = s
  }
  scheduleJobRun() {
    this.scheduled ||
      (requestAnimationFrame(() => {
        this.tryRunJobs(), (this.scheduled = !1)
      }),
      (this.scheduled = !0))
  }
}
import n from "../other/543-91283"
function i(e) {
  return e === n.tE || e === n.ig
}
function o(e, t) {
  return e.__lastFrameVisited === t && e.__used
}
function a(e, t) {
  e.__lastFrameVisited !== t &&
    ((e.__lastFrameVisited = t),
    (e.__used = !1),
    (e.__inFrustum = !1),
    (e.__isLeaf = !1),
    (e.__visible = !1),
    (e.__active = !1),
    (e.__error = 1 / 0),
    (e.__distanceFromCamera = 1 / 0),
    (e.__childrenWereVisible = !1),
    (e.__allChildrenLoaded = !1))
}
function l(e, t, r) {
  if ((a(e, t), (e.__used = !0), r.markUsed(e), e.__contentEmpty)) {
    const s = e.children
    for (let e = 0, n = s.length; e < n; e++) l(s[e], t, r)
  }
}
function c(e, t, r) {
  if (e.__contentEmpty && (!e.__externalTileSet || i(e.__loadingState))) {
    const s = e.children
    for (let e = 0, n = s.length; e < n; e++) {
      const n = s[e]
      ;(n.__depthFromRenderedParent = t), c(n, t, r)
    }
  } else r.requestTileContents(e)
}
function h(e, t = null, r = null, s = null, n = 0) {
  if (t && t(e, s, n)) return void (r && r(e, s, n))
  const i = e.children
  for (let s = 0, o = i.length; s < o; s++) h(i[s], t, r, e, n + 1)
  r && r(e, s, n)
}
function u(e, t) {
  const r = t.stats,
    s = t.frameCount,
    n = t.errorTarget,
    i = t.maxDepth,
    o = t.loadSiblings,
    c = t.lruCache,
    h = t.stopAtEmptyTiles
  a(e, s)
  if (!1 === t.tileInView(e)) return !1
  if (((e.__used = !0), c.markUsed(e), (e.__inFrustum = !0), r.inFrustum++, (h || !e.__contentEmpty) && !e.__externalTileSet)) {
    t.calculateError(e)
    if (e.__error <= n) return !0
    if (t.maxDepth > 0 && e.__depth + 1 >= i) return !0
  }
  let d = !1
  const p = e.children
  for (let e = 0, r = p.length; e < r; e++) {
    const r = u(p[e], t)
    d = d || r
  }
  if (d && o)
    for (let e = 0, t = p.length; e < t; e++) {
      l(p[e], s, c)
    }
  return !0
}
function d(e, t) {
  const r = t.stats,
    s = t.frameCount
  if (!o(e, s)) return
  r.used++
  const a = e.children
  let l = !1
  for (let e = 0, t = a.length; e < t; e++) {
    const t = a[e]
    l = l || o(t, s)
  }
  if (l) {
    let r = !1,
      l = !0
    for (let e = 0, c = a.length; e < c; e++) {
      const c = a[e]
      if ((d(c, t), (r = r || c.__wasSetVisible || c.__childrenWereVisible), o(c, s))) {
        const e = c.__allChildrenLoaded || (!c.__contentEmpty && i(c.__loadingState)) || (c.__externalTileSet && c.__loadingState === n.ig)
        l = l && e
      }
    }
    ;(e.__childrenWereVisible = r), (e.__allChildrenLoaded = l)
  } else e.__isLeaf = !0
}
function p(e, t) {
  const r = t.stats,
    s = t.frameCount
  if (!o(e, s)) return
  const a = e.parent,
    l = a ? a.__depthFromRenderedParent : -1
  e.__depthFromRenderedParent = l
  const h = t.lruCache
  if (e.__isLeaf)
    return (
      e.__depthFromRenderedParent++,
      void (e.__loadingState === n.tE
        ? (e.__inFrustum && ((e.__visible = !0), r.visible++), (e.__active = !0), r.active++)
        : h.isFull() || (e.__contentEmpty && !e.__externalTileSet) || t.requestTileContents(e))
    )
  const u = (t.errorTarget + 1) * t.errorThreshold,
    d = e.__error <= u,
    f = d || "ADD" === e.refine,
    m = !e.__contentEmpty,
    g = m || e.__externalTileSet,
    _ = i(e.__loadingState) && g,
    b = e.__childrenWereVisible,
    T = e.children
  let x = e.__allChildrenLoaded
  if (
    (f && m && e.__depthFromRenderedParent++,
    f && !_ && !h.isFull() && g && t.requestTileContents(e),
    ((d && !x && !b && _) || ("ADD" === e.refine && _)) && (e.__inFrustum && ((e.__visible = !0), r.visible++), (e.__active = !0), r.active++),
    "ADD" !== e.refine && d && !x && _)
  )
    for (let r = 0, n = T.length; r < n; r++) {
      const n = T[r]
      o(n, s) && !h.isFull() && ((n.__depthFromRenderedParent = e.__depthFromRenderedParent + 1), c(n, n.__depthFromRenderedParent, t))
    }
  else
    for (let e = 0, r = T.length; e < r; e++) {
      const r = T[e]
      o(r, s) && p(r, t)
    }
}
function f(e, t) {
  const r = o(e, t.frameCount)
  if (r || e.__usedLastFrame) {
    let s = !1,
      i = !1
    r && ((s = e.__active), (i = (t.displayActiveTiles && e.__active) || e.__visible)),
      e.__contentEmpty || e.__loadingState !== n.tE || (e.__wasSetActive !== s && t.setTileActive(e, s), e.__wasSetVisible !== i && t.setTileVisible(e, i)),
      (e.__wasSetActive = s),
      (e.__wasSetVisible = i),
      (e.__usedLastFrame = r)
    const o = e.children
    for (let e = 0, r = o.length; e < r; e++) {
      f(o[e], t)
    }
  }
}
const m = (e, t) =>
  e.__depth !== t.__depth
    ? e.__depth > t.__depth
      ? -1
      : 1
    : e.__inFrustum !== t.__inFrustum
    ? e.__inFrustum
      ? 1
      : -1
    : e.__used !== t.__used
    ? e.__used
      ? 1
      : -1
    : e.__error !== t.__error
    ? e.__error > t.__error
      ? 1
      : -1
    : e.__distanceFromCamera !== t.__distanceFromCamera
    ? e.__distanceFromCamera > t.__distanceFromCamera
      ? -1
      : 1
    : 0
const g = e => 1 / (e.__depthFromRenderedParent + 1)

import * as THREE from "three"

import B3DMLoader from "../loader/B3DMLoader"
import CMPTLoader from "../loader/CMPTLoader"
import PNTSLoader from "../loader/PNTSLoader"
import I3DMLoader from "../loader/I3DMLoader"

class CustomTileParser {
  manager: any
  extension: string
  constructor(e = THREE.DefaultLoadingManager, t = "") {
    ;(this.manager = e), (this.extension = `path.${t || "unknown"}`)
  }
  parse(e) {
    const t = this.manager,
      r = this.extension
    return new Promise((s, n) => {
      t.getHandler(r).parse(
        e,
        null,
        e => {
          s(e)
        },
        n
      )
    })
  }
}
const L = new THREE.Matrix4()
class TilesGroup extends THREE.Group {
  tilesRenderer: any
  constructor(e) {
    super(), (this.name = "TilesRenderer.TilesGroup"), (this.tilesRenderer = e)
  }
  raycast(e, t) {
    this.tilesRenderer.optimizeRaycast && this.tilesRenderer.raycast(e, t)
  }
  updateMatrixWorld(e) {
    if ((this.matrixAutoUpdate && this.updateMatrix(), this.matrixWorldNeedsUpdate || e)) {
      null === this.parent ? L.copy(this.matrix) : L.multiplyMatrices(this.parent.matrixWorld, this.matrix), (this.matrixWorldNeedsUpdate = !1)
      const e = L.elements,
        t = this.matrixWorld.elements
      let r = !1
      for (let s = 0; s < 16; s++) {
        const n = e[s],
          i = t[s]
        if (Math.abs(n - i) > Number.EPSILON) {
          r = !0
          break
        }
      }
      if (r) {
        this.matrixWorld.copy(L)
        const e = this.children
        for (let t = 0, r = e.length; t < r; t++) e[t].updateMatrixWorld()
      }
    }
  }
}
const A = new THREE.Sphere()
const E = new THREE.Matrix4()
const R = new THREE.Vector3()
const D = new THREE.Vector3()
const U = new THREE.Ray()
const P = []
function k(e, t) {
  return e.distance - t.distance
}
function O(e, t, r) {
  e.traverse(e => {
    Object.getPrototypeOf(e).raycast.call(e, t, r)
  })
}
function F(e, t, r, s) {
  if (r.has(e)) {
    if ((O(e.cached.scene, s, P), P.length > 0)) {
      P.length > 1 && P.sort(k)
      const e = P[0]
      return (P.length = 0), e
    }
    return null
  }
  const n = [],
    i = e.children
  for (let e = 0, r = i.length; e < r; e++) {
    const r = i[e],
      o = r.cached,
      a = t.matrixWorld
    E.copy(a)
    const l = o.sphere
    if (l && (A.copy(l), A.applyMatrix4(E), !s.ray.intersectsSphere(A))) continue
    const c = o.box,
      h = o.boxTransform
    if (c) {
      if ((E.multiply(h).invert(), U.copy(s.ray), U.applyMatrix4(E), !U.intersectBox(c, R))) continue
      {
        let e
        D.setFromMatrixScale(E),
          (e = D.x),
          Math.abs(Math.max(D.x - D.y, D.x - D.z)) > 1e-6 &&
            console.warn("ThreeTilesRenderer : Non uniform scale used for tile which may cause issues when raycasting.")
        let t = { distance: 1 / 0, tile: null }
        n.push(t), (t.distance = R.distanceToSquared(U.origin) * e * e), (t.tile = r)
      }
    }
  }
  n.sort(k)
  let o = 1 / 0,
    a = null
  for (let e = 0, i = n.length; e < i; e++) {
    const i = n[e]
    if (i.distance > o) break
    {
      const e = i.tile,
        n = e.cached.scene
      let l = null
      if ((r.has(e) ? (O(n, s, P), P.length > 0 && (P.length > 1 && P.sort(k), (l = P[0]))) : (l = F(e, t, r, s)), l)) {
        const e = l.distance * l.distance
        e < o && ((o = e), (a = l)), (P.length = 0)
      }
    }
  }
  return a
}
function I(e, t, r, s, n) {
  const i = e.cached,
    o = t.matrixWorld
  E.copy(o)
  const a = i.sphere
  if (a && (A.copy(a), A.applyMatrix4(E), !s.ray.intersectsSphere(A))) return
  const l = i.box,
    c = i.boxTransform
  if (l && (E.multiply(c).invert(), U.copy(s.ray).applyMatrix4(E), !U.intersectsBox(l))) return
  const h = i.scene
  if (r.has(e)) return void O(h, s, n)
  const u = e.children
  for (let e = 0, i = u.length; e < i; e++) I(u[e], t, r, s, n)
}
const V = Symbol("INITIAL_FRUSTUM_CULLED")
const N = (THREE.MathUtils.DEG2RAD, new THREE.Matrix4())
const B = new THREE.Matrix4()
const G = new THREE.Vector3()
const z = new THREE.Vector3()
const H = new THREE.Vector3()
const $ = new THREE.Vector3()
const W = new THREE.Vector3(1, 0, 0)
const j = new THREE.Vector3(0, 1, 0)
function J(e, t) {
  e.traverse(e => {
    e.frustumCulled = e[V] && t
  })
}
class TilesRendererBase {
  tileSets: any
  rootURL: any
  fetchOptions: {}
  preprocessURL: any
  lruCache: LRUCache
  downloadQueue: PriorityQueue
  parseQueue: PriorityQueue
  stats: { parsing: number; downloading: number; failed: number; inFrustum: number; used: number; active: number; visible: number }
  frameCount: number
  errorTarget: number
  errorThreshold: number
  loadSiblings: boolean
  displayActiveTiles: boolean
  maxDepth: number
  stopAtEmptyTiles: boolean
  public _autoDisableRendererCulling: any
  get rootTileSet() {
    const e = this.tileSets[this.rootURL]
    return !e || e instanceof Promise ? null : e
  }
  get root() {
    const e = this.rootTileSet
    return e ? e.root : null
  }
  constructor(...e) {
    ;(this.tileSets = {}), (this.rootURL = e[0]), (this.fetchOptions = {}), (this.preprocessURL = null)
    const t = new LRUCache()
    t.unloadPriorityCallback = g
    const r = new PriorityQueue()
    ;(r.maxJobs = 4), (r.priorityCallback = m)
    const s = new PriorityQueue()
    ;(s.maxJobs = 1),
      (s.priorityCallback = m),
      (this.lruCache = t),
      (this.downloadQueue = r),
      (this.parseQueue = s),
      (this.stats = {
        parsing: 0,
        downloading: 0,
        failed: 0,
        inFrustum: 0,
        used: 0,
        active: 0,
        visible: 0
      }),
      (this.frameCount = 0),
      (this.errorTarget = 6),
      (this.errorThreshold = 1 / 0),
      (this.loadSiblings = !0),
      (this.displayActiveTiles = !1),
      (this.maxDepth = 1 / 0),
      (this.stopAtEmptyTiles = !0)
  }
  traverse(e, t?) {
    const r = this.tileSets[this.rootURL]
    r && r.root && h(r.root, e, t)
  }
  update() {
    const e = this.stats,
      t = this.lruCache,
      r = this.tileSets,
      s = r[this.rootURL]
    if (!(this.rootURL in r)) return void this.loadRootTileSet(this.rootURL)
    if (!s || !s.root) return
    const n = s.root
    ;(e.inFrustum = 0), (e.used = 0), (e.active = 0), (e.visible = 0), this.frameCount++, u(n, this), d(n, this), p(n, this), f(n, this), t.scheduleUnload()
  }
  parseTile(e, t, r) {
    return null
  }
  disposeTile(e) {}
  preprocessNode(e, t, r) {
    e.content &&
      (!("uri" in e.content) && "url" in e.content && ((e.content.uri = e.content.url), delete e.content.url),
      e.content.uri &&
        (e.content.uri = (function (...e) {
          const t = /^[a-zA-Z]+:\/\//
          let r = -1
          for (let s = 0, n = e.length; s < n; s++) t.test(e[s]) && (r = s)
          if (-1 === r) return path.join(...e).replace(/\\/g, "/")
          {
            const n = r <= 0 ? e : e.slice(r),
              i = n[0].match(t)[0]
            return (n[0] = n[0].substring(i.length)), (i + path.join(...n)).replace(/\\/g, "/")
          }
        })(r, e.content.uri)),
      e.content.boundingVolume &&
        !("box" in e.content.boundingVolume || "sphere" in e.content.boundingVolume || "region" in e.content.boundingVolume) &&
        delete e.content.boundingVolume),
      (e.parent = t),
      (e.children = e.children || [])
    if (e.content && e.content.uri) {
      const t = /\.json$/i.test(e.content.uri)
      ;(e.__externalTileSet = t), (e.__contentEmpty = t)
    } else (e.__externalTileSet = !1), (e.__contentEmpty = !0)
    ;(e.__distanceFromCamera = 1 / 0),
      (e.__error = 1 / 0),
      (e.__inFrustum = !1),
      (e.__isLeaf = !1),
      (e.__usedLastFrame = !1),
      (e.__used = !1),
      (e.__wasSetVisible = !1),
      (e.__visible = !1),
      (e.__childrenWereVisible = !1),
      (e.__allChildrenLoaded = !1),
      (e.__wasSetActive = !1),
      (e.__active = !1),
      (e.__loadingState = n.Jk),
      (e.__loadIndex = 0),
      (e.__loadAbort = null),
      (e.__depthFromRenderedParent = -1),
      null === t ? ((e.__depth = 0), (e.refine = e.refine || "REPLACE")) : ((e.__depth = t.__depth + 1), (e.refine = e.refine || t.refine))
  }
  setTileActive(e, t) {}
  setTileVisible(e, t) {}
  calculateError(e) {}
  tileInView(e) {}
  fetchTileSet(e, t, r = null) {
    return fetch(e, t)
      .then(t => {
        if (t.ok) return t.json()
        throw new Error(`TilesRenderer: Failed to load tileset "${e}" with status ${t.status} : ${t.statusText}`)
      })
      .then(t => {
        const n = t.asset.version
        console.assert("1.0" === n || "0.0" === n || "1.1" === n, 'asset.version is expected to be a string of "1.0" or "0.0"')
        const i = path.dirname(e)
        return h(t.root, (e, t) => this.preprocessNode(e, t, i), null, r, r ? r.__depth : 0), t
      })
  }
  loadRootTileSet(e) {
    const t = this.tileSets
    if (e in t) return t[e] instanceof Error ? Promise.reject(t[e]) : Promise.resolve(t[e])
    {
      const r = this.fetchTileSet(e, this.fetchOptions).then(r => {
        t[e] = r
      })
      return (
        r.catch(r => {
          console.error(r), (t[e] = r)
        }),
        (t[e] = r),
        r
      )
    }
  }
  requestTileContents(e) {
    if (e.__loadingState !== n.Jk) return
    const t = this.stats,
      r = this.lruCache,
      s = this.downloadQueue,
      i = this.parseQueue,
      o = e.__externalTileSet
    r.add(e, e => {
      e.__loadingState === n.br ? (e.__loadAbort.abort(), (e.__loadAbort = null)) : o ? (e.children.length = 0) : this.disposeTile(e),
        e.__loadingState === n.br ? t.downloading-- : e.__loadingState === n.yX && t.parsing--,
        (e.__loadingState = n.Jk),
        e.__loadIndex++,
        i.remove(e),
        s.remove(e)
    }),
      e.__loadIndex++
    const a = e.__loadIndex,
      l = new AbortController(),
      c = l.signal
    t.downloading++, (e.__loadAbort = l), (e.__loadingState = n.br)
    const h = o => {
      e.__loadIndex === a &&
        ("AbortError" !== o.name
          ? (i.remove(e),
            s.remove(e),
            e.__loadingState === n.yX ? t.parsing-- : e.__loadingState === n.br && t.downloading--,
            t.failed++,
            console.error(`TilesRenderer : Failed to load tile at url "${e.content.uri}".`),
            console.error(o),
            (e.__loadingState = n.ig))
          : r.remove(e))
    }
    o
      ? s
          .add(e, e => {
            if (e.__loadIndex !== a) return Promise.resolve()
            const t = this.preprocessURL ? this.preprocessURL(e.content.uri) : e.content.uri
            return this.fetchTileSet(t, Object.assign({ signal: c }, this.fetchOptions), e)
          })
          .then((r: any) => {
            e.__loadIndex === a && (t.downloading--, (e.__loadAbort = null), (e.__loadingState = n.tE), e.children.push(r.root))
          })
          .catch(h)
      : s
          .add(e, e => {
            if (e.__loadIndex !== a) return Promise.resolve()
            const t = this.preprocessURL ? this.preprocessURL(e.content.uri) : e.content.uri
            return fetch(t, Object.assign({ signal: c }, this.fetchOptions))
          })
          .then((t: any) => {
            if (e.__loadIndex === a) {
              if (t.ok) return t.arrayBuffer()
              throw new Error(`Failed to load model with error code ${t.status}`)
            }
          })
          .then(r => {
            if (e.__loadIndex === a)
              return (
                t.downloading--,
                t.parsing++,
                (e.__loadAbort = null),
                (e.__loadingState = n.yX),
                i.add(e, e => {
                  if (e.__loadIndex !== a) return Promise.resolve()
                  const t = e.content.uri.split(/\./g).pop()
                  return this.parseTile(r, e, t)
                })
              )
            return null
          })
          .then(() => {
            e.__loadIndex === a &&
              (t.parsing--, (e.__loadingState = n.tE), e.__wasSetVisible && this.setTileVisible(e, !0), e.__wasSetActive && this.setTileActive(e, !0))
          })
          .catch(h)
  }
  dispose() {
    const e = this.lruCache
    this.traverse(t => {
      e.remove(t)
    })
  }
}
export default class TilesRenderer extends TilesRendererBase {
  group: TilesGroup
  cameras: any[]
  cameraMap: Map<any, any>
  cameraInfo: any[]
  activeTiles: Set<any>
  visibleTiles: Set<any>
  optimizeRaycast: boolean
  onLoadTileSet: any
  onLoadModel: any
  onDisposeModel: any
  tileContentParsers: Map<any, any>

  manager: THREE.LoadingManager
  _overridenRaycast: (e: any, t: any) => void

  get autoDisableRendererCulling() {
    return this._autoDisableRendererCulling
  }
  set autoDisableRendererCulling(e) {
    this._autoDisableRendererCulling !== e &&
      ((super["_autoDisableRendererCulling"] = e),
      this.forEachLoadedModel(t => {
        J(t, !e)
      }))
  }
  constructor(...e) {
    super(...e),
      (this.group = new TilesGroup(this)),
      (this.cameras = []),
      (this.cameraMap = new Map()),
      (this.cameraInfo = []),
      (this.activeTiles = new Set()),
      (this.visibleTiles = new Set()),
      (this._autoDisableRendererCulling = !0),
      (this.optimizeRaycast = !0),
      (this.onLoadTileSet = null),
      (this.onLoadModel = null),
      (this.onDisposeModel = null),
      (this.tileContentParsers = new Map())
    const t = new THREE.LoadingManager()
    t.setURLModifier(e => (this.preprocessURL ? this.preprocessURL(e) : e)), (this.manager = t)
    const r = this
    ;(this._overridenRaycast = function (e, t) {
      r.optimizeRaycast || Object.getPrototypeOf(this).raycast.call(this, e, t)
    }),
      this.registerTileContentParser("b3dm", B3DMLoader),
      this.registerTileContentParser("i3dm", I3DMLoader),
      this.registerTileContentParser("cmpt", CMPTLoader),
      this.registerTileContentParser("gltf", CustomTileParser),
      this.registerTileContentParser("glb", CustomTileParser)
  }
  getBounds(e) {
    if (!this.root) return !1
    const t = this.root.cached,
      r = t.box,
      s = t.boxTransform
    return !!r && (e.copy(r), e.applyMatrix4(s), !0)
  }
  getOrientedBounds(e, t) {
    if (!this.root) return !1
    const r = this.root.cached,
      s = r.box,
      n = r.boxTransform
    return !!s && (e.copy(s), t.copy(n), !0)
  }
  getBoundingSphere(e) {
    if (!this.root) return !1
    const t = this.root.cached.sphere
    return !!t && (e.copy(t), !0)
  }
  forEachLoadedModel(e) {
    this.traverse(t => {
      const r = t.cached.scene
      r && e(r, t)
    })
  }
  raycast(e, t) {
    if (this.root)
      if (e.firstHitOnly) {
        const r = F(this.root, this.group, this.activeTiles, e)
        r && t.push(r)
      } else I(this.root, this.group, this.activeTiles, e, t)
  }
  hasCamera(e) {
    return this.cameraMap.has(e)
  }
  setCamera(e) {
    const t = this.cameras,
      r = this.cameraMap
    return !r.has(e) && (r.set(e, new THREE.Vector2()), t.push(e), !0)
  }
  setResolution(e, t, r) {
    const s = this.cameraMap
    return !!s.has(e) && (t instanceof THREE.Vector2 ? s.get(e).copy(t) : s.get(e).set(t, r), !0)
  }
  setResolutionFromRenderer(e, t) {
    const r = this.cameraMap
    if (!r.has(e)) return !1
    const s = r.get(e)
    return t.getSize(s), s.multiplyScalar(t.getPixelRatio()), !0
  }
  deleteCamera(e) {
    const t = this.cameras,
      r = this.cameraMap
    if (r.has(e)) {
      const s = t.indexOf(e)
      return t.splice(s, 1), r.delete(e), !0
    }
    return !1
  }
  fetchTileSet(...t) {
    const url = t[0]
    const r = super.fetchTileSet(url, t[1], t[2])
    return (
      r.then(t => {
        this.onLoadTileSet &&
          Promise.resolve().then(() => {
            this.onLoadTileSet(t, url)
          })
      }),
      r
    )
  }
  update() {
    const e = this.group,
      t = this.cameras,
      r = this.cameraMap,
      s = this.cameraInfo
    if (0 === t.length) return void console.warn("TilesRenderer: no cameras defined. Cannot update 3d tiles.")
    for (; s.length > t.length; ) s.pop()
    for (; s.length < t.length; )
      s.push({
        frustum: new THREE.Frustum(),
        isOrthographic: !1,
        sseDenominator: -1,
        position: new THREE.Vector3(),
        invScale: -1,
        pixelSize: 0
      })
    let n
    B.copy(e.matrixWorld).invert(),
      G.setFromMatrixScale(B),
      (n = G.x),
      Math.abs(Math.max(G.x - G.y, G.x - G.z)) > 1e-6 &&
        console.warn("ThreeTilesRenderer : Non uniform scale used for tile which may cause issues when calculating screen space error.")
    for (let i = 0, o = s.length; i < o; i++) {
      const o = t[i],
        a = s[i],
        l = a.frustum,
        c = a.position,
        h = r.get(o)
      ;(0 !== h.width && 0 !== h.height) || console.warn("TilesRenderer: resolution for camera error calculation is not set.")
      const u = o.projectionMatrix.elements
      if (((a.isOrthographic = 1 === u[15]), a.isOrthographic)) {
        const e = 2 / u[0],
          t = 2 / u[5]
        a.pixelSize = Math.max(t / h.height, e / h.width)
      } else a.sseDenominator = 2 / u[5] / h.height
      ;(a.invScale = n),
        N.copy(e.matrixWorld),
        N.premultiply(o.matrixWorldInverse),
        N.premultiply(o.projectionMatrix),
        l.setFromProjectionMatrix(N),
        c.set(0, 0, 0),
        c.applyMatrix4(o.matrixWorld),
        c.applyMatrix4(B)
    }
    super.update()
  }
  preprocessNode(e, t, r) {
    super.preprocessNode(e, t, r)
    const s = new THREE.Matrix4()
    if (e.transform) {
      const t = e.transform
      for (let e = 0; e < 16; e++) s.elements[e] = t[e]
    } else s.identity()
    t && s.premultiply(t.cached.transform)
    const n = new THREE.Matrix4().copy(s).invert()
    let i = null,
      o = null,
      a = null
    if ("box" in e.boundingVolume) {
      const t = e.boundingVolume.box
      ;(i = new THREE.Box3()), (o = new THREE.Matrix4()), (a = new THREE.Matrix4()), z.set(t[3], t[4], t[5]), H.set(t[6], t[7], t[8]), $.set(t[9], t[10], t[11])
      const r = z.length(),
        n = H.length(),
        l = $.length()
      z.normalize(),
        H.normalize(),
        $.normalize(),
        0 === r && z.crossVectors(H, $),
        0 === n && H.crossVectors(z, $),
        0 === l && $.crossVectors(z, H),
        o.set(z.x, H.x, $.x, t[0], z.y, H.y, $.y, t[1], z.z, H.z, $.z, t[2], 0, 0, 0, 1),
        o.premultiply(s),
        a.copy(o).invert(),
        i.min.set(-r, -n, -l),
        i.max.set(r, n, l)
    }
    let l = null
    if ("sphere" in e.boundingVolume) {
      const t = e.boundingVolume.sphere
      ;(l = new THREE.Sphere()), l.center.set(t[0], t[1], t[2]), (l.radius = t[3]), l.applyMatrix4(s)
    } else if ("box" in e.boundingVolume) {
      const t = e.boundingVolume.box
      ;(l = new THREE.Sphere()), i.getBoundingSphere(l), l.center.set(t[0], t[1], t[2]), l.applyMatrix4(s)
    }
    "region" in e.boundingVolume && console.warn("ThreeTilesRenderer: region bounding volume not supported."),
      (e.cached = {
        loadIndex: 0,
        transform: s,
        transformInverse: n,
        active: !1,
        inFrustum: [],
        box: i,
        boxTransform: o,
        boxTransformInverse: a,
        sphere: l,
        region: null,
        scene: null,
        geometry: null,
        material: null
      })
  }
  registerTileContentParser(e, t) {
    this.tileContentParsers.has(e) ? console.warn(`TilesRenderer: Content type "${e}" already registered.`) : this.tileContentParsers.set(e, t)
  }
  parseTile(e, t, r) {
    ;(t._loadIndex = t._loadIndex || 0), t._loadIndex++
    const s = t.content.uri.split(/[\\\/]/g)
    s.pop()
    const n = s.join("/"),
      i = this.fetchOptions,
      o = this.tileContentParsers,
      a = this.manager,
      l = t._loadIndex
    let c = null
    if (o.has(r)) {
      const t = new (o.get(r))(a, r)
      ;(t.workingPath = n), (t.fetchOptions = i), (c = t.parse(e).then(e => e.scene))
    } else
      switch (r) {
        case "pnts":
          c = Promise.resolve(new PNTSLoader(a).parse(e).scene)
          break
        default:
          console.warn(`TilesRenderer: Content type "${r}" not supported.`), (c = Promise.resolve(null))
      }
    return c.then(e => {
      if (t._loadIndex !== l) return
      const s = (this.rootTileSet.asset && this.rootTileSet.asset.gltfUpAxis) || "y",
        n = t.cached,
        i = n.transform
      switch (s.toLowerCase()) {
        case "x":
          N.makeRotationAxis(j, -Math.PI / 2)
          break
        case "y":
          N.makeRotationAxis(W, Math.PI / 2)
          break
        case "z":
          N.identity()
      }
      e.updateMatrix(),
        "pnts" !== r && e.matrix.multiply(N),
        e.matrix.premultiply(i),
        e.matrix.decompose(e.position, e.quaternion, e.scale),
        e.traverse(e => {
          e[V] = e.frustumCulled
        }),
        J(e, !this.autoDisableRendererCulling),
        (n.scene = e),
        e.traverse(e => {
          e.raycast = this._overridenRaycast
        })
      const o = [],
        a = [],
        c = []
      e.traverse(e => {
        if ((e.geometry && a.push(e.geometry), e.material)) {
          const t = e.material
          o.push(e.material)
          for (const e in t) {
            const r = t[e]
            r && r.isTexture && c.push(r)
          }
        }
      }),
        (n.materials = o),
        (n.geometry = a),
        (n.textures = c),
        this.onLoadModel && this.onLoadModel(e, t)
    })
  }
  disposeTile(e) {
    const t = e.cached
    if (t.scene) {
      const r = t.materials,
        s = t.geometry,
        n = t.textures
      for (let e = 0, t = s.length; e < t; e++) s[e].dispose()
      for (let e = 0, t = r.length; e < t; e++) r[e].dispose()
      for (let e = 0, t = n.length; e < t; e++) {
        n[e].dispose()
      }
      this.onDisposeModel && this.onDisposeModel(t.scene, e), (t.scene = null), (t.materials = null), (t.textures = null), (t.geometry = null)
    }
    e._loadIndex++
  }
  setTileVisible(e, t) {
    const r = e.cached.scene,
      s = this.visibleTiles,
      n = this.group
    t ? (n.add(r), s.add(e), r.updateMatrixWorld(!0)) : (n.remove(r), s.delete(e))
  }
  setTileActive(e, t) {
    const r = this.activeTiles
    t ? r.add(e) : r.delete(e)
  }
  calculateError(e) {
    const t = e.cached,
      r = t.inFrustum,
      s = this.cameras,
      n = this.cameraInfo,
      i = e.boundingVolume
    if ("box" in i || "sphere" in i) {
      const i = t.sphere,
        o = t.box,
        a = t.boxTransformInverse,
        l = t.transformInverse,
        c = o && a
      let h = -1 / 0,
        u = 1 / 0
      for (let t = 0, d = s.length; t < d; t++) {
        if (!r[t]) continue
        const s = n[t],
          d = s.invScale
        let p
        if (s.isOrthographic) {
          const t = s.pixelSize
          p = e.geometricError / (t * d)
        } else {
          let t
          G.copy(s.position), c ? (G.applyMatrix4(a), (t = o.distanceToPoint(G))) : (G.applyMatrix4(l), (t = Math.max(i.distanceToPoint(G), 0)))
          const r = t * d,
            n = s.sseDenominator
          ;(p = e.geometricError / (r * n)), (u = Math.min(u, r))
        }
        h = Math.max(h, p)
      }
      ;(e.__distanceFromCamera = u), (e.__error = h)
    } else "region" in i && console.warn("ThreeTilesRenderer : Region bounds not supported.")
  }
  tileInView(e) {
    const t = e.cached,
      r = t.sphere,
      s = t.inFrustum
    if (r) {
      const e = this.cameraInfo
      let t = !1
      for (let n = 0, i = e.length; n < i; n++) {
        e[n].frustum.intersectsSphere(r) ? ((t = !0), (s[n] = !0)) : (s[n] = !1)
      }
      return t
    }
    return !0
  }
}
